package com.fourhats.controller;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.sql.Date;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import com.fourhats.exception.UserEmailDoesNotExist;
import com.fourhats.exception.UserOldPasswordDoesNotMatch;
import com.fourhats.model.ObjectTypes;
import com.fourhats.model.UploadedFile;
import com.fourhats.model.User;
import com.fourhats.services.EmailService;
import com.fourhats.services.MarketService;
import com.fourhats.services.UserService;
import com.fourhats.services.VisitEntityService;
import com.fourhats.services.dto.UserDto;
import com.fourhats.services.util.FileHelper;
import com.fourhats.services.util.ImageInfo;
import com.google.gson.Gson;

@Controller
public class UserController extends GenericController {
	
	@Autowired
	private UserService userService;
	
	@Autowired
	private MarketService marketService;
	
	@Autowired
	private EmailService emailService;
	
	@Autowired
	private VisitEntityService entityVisitService;
	
	@Value("#{configProps}")
	private Properties properties;
	
	@Autowired
	@Qualifier("org.springframework.security.authenticationManager")
	protected AuthenticationManager authenticationManager;
	
	private final String SMALL_AVATAR_FOLDER = "small";
	private final String MEDIUM_AVATAR_FOLDER = "medium";
	private final String LARGE_AVATAR_FOLDER = "large";
	private final String ORIGINAL_FOLDER = "originals";
	/*Temp*/
	private final String ORIGINAL_TEMP_FOLDER = "originals";
	
	@RequestMapping("/register")
    public String goToRegister(ModelMap model) {
		if(super.isUserLogged()) {
			return "redirect:/home";
		}
		
		model.addAttribute("personAttribute", new User());
		return "content/registerPage";
	}
	
	@RequestMapping("/user/profile")
    public String goToUserProfile(ModelMap model) {
		try {
			super.verifyAuthentication();
		} catch (Exception e) {
			return "redirect:/home"; 
		}
		
		bindUserProfile(model);
		return "content/userProfile";
	}
	
	@RequestMapping(value = "/register_new", method = RequestMethod.POST)
    public String addUser(@ModelAttribute("personAttribute") User user, BindingResult result, HttpServletRequest request, HttpServletResponse response, Model model) throws Exception {
		if (result.hasErrors()) {
		   return "content/registerPage";
		}
		
		if(userService.existUser(user.getEmail())) {
			model.addAttribute("existingEmailError", "true");
			return "redirect:/register";
		}
		
		String date = user.getBirthdayString().substring(6, 10) + "-" + user.getBirthdayString().substring(3, 5) + "-" + user.getBirthdayString().substring(0, 2);
		
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd", new Locale("es", "ES"));
		try {
			user.setBirthday(new Date(sdf.parse(date).getTime()));
		} catch (ParseException e) {
			return "content/registerPage";
		}

		user.setUsername(user.getEmail());
		user.setEnable(true);
		userService.addUser(user);
		
		copyToAvatarFolder(user.getAvatarPath());

		authenticateUserAndSetSession(user, request);

		try {
			Map<String, String> values = new HashMap<String, String>();
			values.put("{UserName}", user.getName());
			this.emailService.sendEMail(user.getEmail(), "Bienvenido a La Tienda Sustentable", this.properties.getProperty("folder.emails"), "registrationEmail", values);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		model.addAttribute("successRegistration", "ok");
		return "redirect:/home";
    }
	
	@RequestMapping(value="/user/editUser", method= RequestMethod.POST)
	public @ResponseBody void editUser(@RequestBody UserDto user) {
		String date = user.getBirthdayString().substring(6, 10) + "-" + user.getBirthdayString().substring(3, 5) + "-" + user.getBirthdayString().substring(0, 2);
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd", new Locale("es", "ES"));
		try {
			user.setBirthday(new Date(sdf.parse(date).getTime()));
		} catch (ParseException e) {
			return;
		}
		
		userService.editUser(user);
	}
	
	@RequestMapping(value="/user/askForNewPassword", method= RequestMethod.GET)
	public String askForNewPassword(ModelMap model, String userEmail) {
		String newPassword = "";
		try {
			newPassword = this.userService.createNewPassword(userEmail);
		} catch (UserEmailDoesNotExist e) {
			model.addAttribute("noExistUserWithEmailError", "true");
			return "redirect:/home";
		}
		
		User user = this.userService.getByUsername(userEmail);
		
		Map<String, String> values = new HashMap<String, String>();
		values.put("{UserName}", user.getName());
		values.put("{NewPassword}", newPassword);
		
		try {
			this.emailService.sendEMail(user.getEmail(), "Nuevo contrase&ntilde;a - La Tienda Sustentable", this.properties.getProperty("folder.emails"), "recoverPasswordEmail", values);
		} catch (Exception e) {
			model.addAttribute("emailNotSentError", "true");
			return "redirect:/home";
		}
		
		model.addAttribute("emailSentSuccessfully", "emailSentSuccessfully");
		return "redirect:/home";
	}
	
	@RequestMapping(value="/user/changePassword", method= RequestMethod.POST)
	public String changePassword(HttpServletRequest request, ModelMap model) {
		String userId = request.getParameter("userId");
		String oldPassword = request.getParameter("password_old");
		String newPassword = request.getParameter("password_new");
		String confirmPassword = request.getParameter("password_confirm");
		
		if(!newPassword.equals(confirmPassword)) {
			model.addAttribute("newPasswordNoMatch", "newPasswordNoMatch");
			return "redirect:/user/profile";
		}
		
		try {
			userService.changePassword(Long.parseLong(userId), oldPassword, newPassword);
		} catch (UserOldPasswordDoesNotMatch e) {
			model.addAttribute("oldPasswordNoMatch", "oldPasswordNoMatch");
			return "redirect:/user/profile";
		}
		
		model.addAttribute("changePasswordSuccess", "changePasswordSuccess");
		return "redirect:/user/profile";
	}
	
	@RequestMapping(value="/user/updateAvatar", method= RequestMethod.GET, headers="Accept=*/*")
	public @ResponseBody void UpdateAvatar(long userId, String avatarPath) {
		userService.updateAvatar(userId, avatarPath);
	}
	
	@RequestMapping(value="/user/isLogged",
	method = RequestMethod.GET, 
	headers="Accept=*/*")
	public @ResponseBody String isLogged() {
		super.verifyAuthentication();
		return super.SUCCESS_MESSAGE;
	}
	
	@RequestMapping(value="/user/hasMarket",
	method = RequestMethod.GET, 
	headers="Accept=*/*")
	public @ResponseBody boolean hasMarket() {
		super.verifyAuthentication();
		return marketService.hasMarket(super.getUserId());
	}
	
	@RequestMapping(value="/user/getCurrentUserAvatar",
	method = RequestMethod.GET)
	public @ResponseBody String getCurrentUserAvatar() {
		if(super.isUserLogged()) {
			UserDto user = this.userService.getUserById(super.getUserId()); 
			return user.getAvatarPath();
		} else {
			return "";
		}
	}
	
	@RequestMapping(value="/user/image/uploadAvatarCrop", method=RequestMethod.POST)
	public @ResponseBody UploadedFile uploadAvatarCrop(MultipartHttpServletRequest request, HttpServletResponse response) throws IOException {
		String tempPath = properties.getProperty("folder.avatar");
		return FileHelper.getUploadedFile(request, tempPath);
	}
	
	@RequestMapping(value = "/user/userVisitProductProfile", method = RequestMethod.GET, headers="Accept=*/*")
	public @ResponseBody void userVisitProductProfile() {
		long userId = this.getUserId();
		entityVisitService.addVisitEntity(ObjectTypes.SALES_PROFILE.getValue(), userId, userId);
	}
	
	@RequestMapping(value = "/user/userVisitQuestionProfile", method = RequestMethod.GET, headers="Accept=*/*")
	public @ResponseBody void userVisitQuestionProfile() {
		long userId = this.getUserId();
		entityVisitService.addVisitEntity(ObjectTypes.QUESTION_PROFILE.getValue(), userId, userId);
	}
	
	private void copyToAvatarFolder(String avatarPath) throws Exception {
		if(avatarPath == ""){
			return;
		}
		
		String tempPath = properties.getProperty("folder.temp");
		String targetPath = properties.getProperty("folder.avatar");
		List<ImageInfo> imagesInfo = new ArrayList<ImageInfo>();
		imagesInfo.add(new ImageInfo(SMALL_AVATAR_FOLDER, 125, 100));
		imagesInfo.add(new ImageInfo(MEDIUM_AVATAR_FOLDER, 275, 191));
		
		BufferedImage imageSrc = null;
		try{
			File file = new File(tempPath, avatarPath);
			imageSrc = ImageIO.read(file);
			byte [] imageBytes = FileHelper.bufferedImageToByte(imageSrc, FilenameUtils.getExtension(avatarPath));
			imagesInfo.add(new ImageInfo(LARGE_AVATAR_FOLDER, imageSrc.getWidth(), imageSrc.getHeight()));
			FileHelper.generateImages2(imageBytes, targetPath, avatarPath, imagesInfo);
			
			String src = FileHelper.getFullPath(tempPath, ORIGINAL_TEMP_FOLDER, avatarPath);
			String dst = FileHelper.getFullPath(targetPath, ORIGINAL_FOLDER, avatarPath);
			FileHelper.copyFile(src, dst);
		}catch(Exception e){
			throw e;
		}finally{
			if(imageSrc != null){
				imageSrc.flush();
			}
		}
	}
	
	private void bindUserProfile(ModelMap model) {
		UserDto currentUser = userService.getUserById(super.getUserId());
		Gson gson = new Gson();
		model.addAttribute("userInfo", gson.toJson(currentUser).toString());
	}
	
	private void authenticateUserAndSetSession(User user, HttpServletRequest request) {
		UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(user.getEmail(), user.getPassword());
		token.setDetails(new WebAuthenticationDetails(request));
		
		try {
			Authentication auth = authenticationManager.authenticate(token);
			SecurityContextHolder.getContext().setAuthentication(auth);
		} catch(Exception e) {
			e.printStackTrace();
		}
	}
}
